import React, { useEffect, useRef, useState, useCallback } from "react";
import { io } from "socket.io-client";
import { useLocation } from "react-router-dom";
import { getAvatarUrl } from "../../utils/avatarGenerator"; // 引入本地头像生成器
import GiftComponent from "../../components/GiftComponent";
import GiftAnimation from "../../components/GiftAnimation";
import "../../components/GiftAnimation.css";

const SERVER_URL = ""; // 使用Vite代理，连接到同源地址
const DEFAULT_AVATAR = "https://api.dicebear.com/7.x/bottts/svg?seed=";
const MAX_MIC = 8;

function useQuery() {
  return new URLSearchParams(useLocation().search);
}

const VoiceRoom = () => {
  const [peers, setPeers] = useState({});
  const [userId, setUserId] = useState(null);
  const [micList, setMicList] = useState([]); // 当前上麦用户
  const [isMic, setIsMic] = useState(false); // 我是否在麦上
  const [roomId, setRoomId] = useState("test-room");
  const [hostId, setHostId] = useState(null); // 主持人id
  const [muteList, setMuteList] = useState([]); // 当前禁麦用户
  const [userList, setUserList] = useState([]); // 房间内所有用户
  const [showJoinModal, setShowJoinModal] = useState(true);
  const [nickname, setNickname] = useState("");
  const [avatar, setAvatar] = useState(() => getAvatarUrl(Date.now().toString()));
  const [micFull, setMicFull] = useState(false);
  const [speakingMap, setSpeakingMap] = useState({}); // {id: true/false}
  const [localStream, setLocalStream] = useState(null); // 新增：用state管理本地流
  const localAudioRef = useRef();
  const remoteAudioRefs = useRef({});
  const localStreamRef = useRef(); // 保留ref用于清理副作用
  const socketRef = useRef();
  const peerConnections = useRef({});
  const iceCandidateQueuesRef = useRef({}); // 新增：用于暂存ICE候选
  const pendingOffersRef = useRef({}); // 新增：用于暂存 offer
  const analyserRefs = useRef({}); // {id: analyserNode}
  const animationFrameRef = useRef();
  const micAnimationRef = useRef(false);
  const [messages, setMessages] = useState([]); // 消息列表
  const messageInputRef = useRef();
  const [background, setBackground] = useState('/assets/bg.jpg'); // 默认背景图
  const fileInputRef = useRef(null);
  const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
  const chatBoxRef = useRef(null); // Ref for chat box scrolling
  const [isGiftModalOpen, setIsGiftModalOpen] = useState(false);
  const [giftQueue, setGiftQueue] = useState([]); // [{ fromUser, gift }]

  const query = useQuery();

  // 设置真实的vh变量，解决移动端键盘弹起时页面压缩的问题
  useEffect(() => {
    const setVh = () => {
      document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`);
    };
    setVh();
    window.addEventListener('resize', setVh);
    return () => window.removeEventListener('resize', setVh);
  }, []);

  // 监听窗口大小变化
  useEffect(() => {
    const handleResize = () => {
      setIsMobile(window.innerWidth < 768);
    };
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  // 音量检测: 本地和远端
  useEffect(() => {
    // 清理上一次的 analyser
    Object.values(analyserRefs.current).forEach(obj => {
      if (obj && obj.source) obj.source.disconnect();
    });
    analyserRefs.current = {};
    setSpeakingMap({});

    // 本地音频流检测
    if (isMic && localAudioRef.current && localAudioRef.current.srcObject) {
      const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
      const source = audioCtx.createMediaStreamSource(localAudioRef.current.srcObject);
      const analyser = audioCtx.createAnalyser();
      analyser.fftSize = 256;
      source.connect(analyser);
      analyserRefs.current[userId] = { analyser, source, ctx: audioCtx };
    }
    // 远端音频流检测
    micList.forEach(id => {
      if (id !== userId && remoteAudioRefs.current[id] && remoteAudioRefs.current[id].srcObject) {
        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        const source = audioCtx.createMediaStreamSource(remoteAudioRefs.current[id].srcObject);
        const analyser = audioCtx.createAnalyser();
        analyser.fftSize = 256;
        source.connect(analyser);
        analyserRefs.current[id] = { analyser, source, ctx: audioCtx };
      }
    });
    // 动画帧检测音量
    function detect() {
      const newMap = {};
      Object.entries(analyserRefs.current).forEach(([id, obj]) => {
        if (!obj.analyser) return;
        const data = new Uint8Array(obj.analyser.frequencyBinCount);
        obj.analyser.getByteFrequencyData(data);
        const avg = data.reduce((a, b) => a + b, 0) / data.length;
        newMap[id] = avg > 20; // 说话阈值
      });
      setSpeakingMap(newMap);
      animationFrameRef.current = requestAnimationFrame(detect);
    }
    detect();
    return () => {
      Object.values(analyserRefs.current).forEach(obj => {
        if (obj && obj.source) obj.source.disconnect();
        if (obj && obj.ctx) obj.ctx.close();
      });
      analyserRefs.current = {};
      if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
    };
    // eslint-disable-next-line
  }, [isMic, micList, userId]);

  useEffect(() => {
    if (showJoinModal) return;
    const room = query.get("room") || "test-room";
    setRoomId(room);
    
    // 优化Socket.io连接配置
    const socket = io(SERVER_URL, {
      reconnectionDelayMax: 10000,
      reconnectionAttempts: 10,
      transports: ['websocket', 'polling'], // 先尝试WebSocket，失败后使用轮询
      forceNew: true,
      path: '/socket.io/', // 显式指定路径
      query: {
        room: room,
        userId: Date.now() // 添加唯一标识符
      },
      timeout: 20000 // 增加超时时间
    });
    
    socketRef.current = socket;
    
    // 连接事件处理
    socket.on('connect', () => {
      console.log('已连接到信令服务器:', socket.id);
      setUserId(socket.id);
      socket.emit("join-room", room, { nickname, avatar });
    });
    
    socket.on('connect_error', (error) => {
      console.error('连接错误:', error);
      alert(`连接服务器失败: ${error.message}，请检查网络连接或刷新页面重试`);
    });

    // 用户加入事件
    socket.on("user-joined", (id) => {
      console.log('用户加入:', id);
    });

    socket.on("offer", ({ offer, from }) => {
      console.log('收到offer:', from);
      if (isMic) createPeerConnection(from, socket, localStreamRef.current, false, offer);
    });

    socket.on("answer", ({ answer, from }) => {
      console.log('收到answer:', from);
      const pc = peerConnections.current[from];
      if (pc) pc.setRemoteDescription(new window.RTCSessionDescription(answer));
    });

    socket.on("ice-candidate", ({ candidate, from }) => {
      console.log('收到ICE候选:', from);
      const pc = peerConnections.current[from];
      if (pc && candidate) pc.addIceCandidate(new window.RTCIceCandidate(candidate));
    });
    
    // 批量处理ICE候选
    socket.on("ice-candidates-batch", ({ candidates, from }) => {
      console.log(`收到批量ICE候选(${candidates.length}个):`, from);
      const pc = peerConnections.current[from];
      if (pc) {
        candidates.forEach(candidate => {
          pc.addIceCandidate(new window.RTCIceCandidate(candidate))
            .catch(err => console.error('添加ICE候选失败:', err));
        });
      }
    });

    socket.on("user-left", (id) => {
      console.log('用户离开:', id);
      if (peerConnections.current[id]) {
        peerConnections.current[id].close();
        delete peerConnections.current[id];
        setPeers(peers => {
          const newPeers = { ...peers };
          delete newPeers[id];
          return newPeers;
        });
      }
    });

    socket.on("mic-list", (list) => {
      console.log('麦克风列表更新:', list);
      setMicList(list);
      const amIOnMic = list.includes(socket.id);
      if (isMic !== amIOnMic) {
        setIsMic(amIOnMic);
      }
    });

    socket.on("host-info", (host) => {
      setHostId(host);
    });

    socket.on("mute-list", (list) => {
      setMuteList(list);
    });

    socket.on("user-list", (list) => {
      setUserList(list);
    });

    socket.on("mic-full", (max) => {
      setMicFull(true);
      setTimeout(() => setMicFull(false), 2000);
    });

    socket.on("receive-message", (msg) => {
      setMessages(msgs => [...msgs, msg]);
    });

    socket.on("receive-gift", (giftData) => { // giftData = { fromUser, gift }
      console.log("收到礼物:", giftData);
      // 添加时间戳，确保每个礼物都是唯一的
      const giftWithTimestamp = {
        ...giftData,
        timestamp: Date.now()
      };
      
      setGiftQueue(prevQueue => {
        console.log("当前礼物队列长度:", prevQueue.length);
        const newQueue = [...prevQueue, giftWithTimestamp];
        console.log("更新后礼物队列长度:", newQueue.length);
        return newQueue;
      });
    });

    // 监听背景更换事件
    socket.on('background-changed', (newBg) => {
      setBackground(newBg);
      // 可选：同时更新本地存储，以便下次刷新时能保留
      localStorage.setItem(`roomBackground_${roomId}`, newBg);
    });

    return () => {
      socket.disconnect();
      Object.values(peerConnections.current).forEach(pc => pc.close());
    };
    // eslint-disable-next-line
  }, [showJoinModal]);

  const cleanupConnections = () => {
      console.log("清理所有WebRTC连接...");
      Object.values(peerConnections.current).forEach(pc => pc.close());
      peerConnections.current = {};
      setPeers({});
  };

  // 采集本地音频流（仅上麦时）
  useEffect(() => {
      if (isMic) {
        const audioConstraints = {
          audio: {
            echoCancellation: true,
            noiseSuppression: true,
            autoGainControl: true,
          }
        };
        
        console.log('正在请求麦克风权限...');
        navigator.mediaDevices.getUserMedia(audioConstraints)
        .then(stream => {
          console.log('麦克风访问成功');
          localStreamRef.current = stream; // 直接存入 ref
          setLocalStream(stream); // 用 state 触发依赖更新
            if (localAudioRef.current) {
            localAudioRef.current.srcObject = stream;
              localAudioRef.current.play().catch(e => console.log('本地音频播放失败:', e));
            }
            
          // **关键修复**：麦克风就绪后，处理所有待办的 offer
          console.log('[Offer Queue] Processing pending offers after getting local stream.');
          Object.keys(pendingOffersRef.current).forEach(fromId => {
            const { offer } = pendingOffersRef.current[fromId];
            console.log(`[Offer Queue] Found pending offer from ${fromId}. Processing...`);
            handleOffer({ offer, from: fromId });
            delete pendingOffersRef.current[fromId]; // 处理后删除
          });

          })
          .catch(err => {
            console.error("获取麦克风失败:", err);
              alert("麦克风访问失败: " + err.message);
            setIsMic(false);
          });
      } else {
      // 下麦时关闭本地流并清理连接
        if (localStreamRef.current) {
          localStreamRef.current.getTracks().forEach(track => track.stop());
          localStreamRef.current = null;
        }
      setLocalStream(null);
      if (localAudioRef.current) localAudioRef.current.srcObject = null;
      
        // 通知服务器下麦
        if (socketRef.current) socketRef.current.emit("down-mic", roomId);
      
      cleanupConnections(); // 清理所有连接
    }
  }, [isMic, roomId]);

  // =================================================================================
  //  WebRTC 信令处理器 (Offer/Answer/Candidate)
  // =================================================================================
  const genAvatar = useCallback(() => {
    setAvatar(getAvatarUrl(Date.now().toString()));
  }, []);

  const createPeerConnection = useCallback((otherUserId, isInitiator) => {
    console.log(`%c[WebRTC] Creating peer connection to ${otherUserId}`, 'color: #3498db; font-weight: bold;');
    
    if (peerConnections.current[otherUserId]) {
        console.warn(`[WebRTC] Closing existing connection to ${otherUserId} before creating a new one.`);
        peerConnections.current[otherUserId].close();
    }

    const pc = new window.RTCPeerConnection({
      iceServers: [
        { urls: 'stun:stun.l.google.com:19302' },
        { urls: 'stun:stun1.l.google.com:19302' },
        { urls: 'stun:stun.services.mozilla.com' },
      ],
    });

    if (localStreamRef.current) {
      localStreamRef.current.getTracks().forEach(track => {
        pc.addTrack(track, localStreamRef.current);
      });
      console.log(`[WebRTC] Added local stream tracks to PC for ${otherUserId}`);
    }

    pc.ontrack = (event) => {
      console.log(`%c[WebRTC] Received remote track from ${otherUserId}`, 'color: #2ecc71; font-weight: bold;', event.streams[0]);
      setPeers(prevPeers => ({
        ...prevPeers,
        [otherUserId]: event.streams[0]
      }));
    };

    pc.onicecandidate = (event) => {
      if (event.candidate) {
        console.log(`[WebRTC] Found ICE candidate for ${otherUserId}. Sending...`);
        if (socketRef.current) {
          socketRef.current.emit('ice-candidate', {
            candidate: event.candidate,
            to: otherUserId,
          });
        }
      }
    };
    
    pc.onconnectionstatechange = () => {
      console.log(`%c[WebRTC] Connection state with ${otherUserId}: ${pc.connectionState}`, 'color: purple');
      if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected' || pc.connectionState === 'closed') {
         if (isInitiator && pc.connectionState === 'failed') {
             console.log(`[WebRTC] Connection with ${otherUserId} failed, attempting ICE restart.`);
             pc.createOffer({ iceRestart: true })
               .then(offer => pc.setLocalDescription(offer))
               .then(() => {
                   socketRef.current.emit('offer', {
                       offer: pc.localDescription,
                       to: otherUserId,
                   });
               })
               .catch(e => console.error(`[WebRTC] ICE restart offer failed for ${otherUserId}:`, e));
         }
      }
    };

    peerConnections.current[otherUserId] = pc;
    return pc;
  }, []);

  const processIceCandidate = useCallback((candidate, from) => {
    const pc = peerConnections.current[from];
    if (!candidate) return;

    if (pc && pc.remoteDescription && pc.remoteDescription.type) {
        pc.addIceCandidate(new RTCIceCandidate(candidate))
          .catch(e => console.error('[Error] Adding ICE candidate directly failed', e));
    } else {
        console.log(`[Signal] Queuing ICE candidate from ${from} because remote description is not set yet.`);
        if (!iceCandidateQueuesRef.current[from]) {
            iceCandidateQueuesRef.current[from] = [];
        }
        iceCandidateQueuesRef.current[from].push(candidate);
    }
  }, []);

  const handleOffer = useCallback(({ offer, from }) => {
    if (!isMic || !localStreamRef.current) {
        console.warn(`[Signal] Received offer from ${from}, but I'm not ready. Queuing it.`);
        pendingOffersRef.current[from] = { offer };
        return;
    }

    console.log(`[Signal] Received and processing offer from ${from}`);
    const pc = createPeerConnection(from, false);

    pc.setRemoteDescription(new RTCSessionDescription(offer))
        .then(() => {
            const queue = iceCandidateQueuesRef.current[from];
            if (queue) {
                console.log(`[WebRTC] Processing ${queue.length} queued ICE candidates for ${from}.`);
                queue.forEach(candidate => {
                    pc.addIceCandidate(new RTCIceCandidate(candidate))
                      .catch(e => console.error('[Error] Adding queued ICE candidate failed', e));
                });
                delete iceCandidateQueuesRef.current[from];
            }
            return pc.createAnswer();
        })
        .then(answer => pc.setLocalDescription(answer))
        .then(() => {
            console.log(`[Signal] Sending answer to ${from}`);
            socketRef.current.emit('answer', {
                answer: pc.localDescription,
                to: from
            });
        })
        .catch(e => console.error('[Error] Answer creation failed', e));
  }, [isMic, createPeerConnection]);

  const handleAnswer = useCallback(({ answer, from }) => {
    console.log(`[Signal] Received answer from ${from}`);
    const pc = peerConnections.current[from];
    if (pc) {
        pc.setRemoteDescription(new RTCSessionDescription(answer))
          .then(() => {
              const queue = iceCandidateQueuesRef.current[from];
              if (queue) {
                  console.log(`[WebRTC] Processing ${queue.length} queued ICE candidates for ${from}.`);
                  queue.forEach(candidate => {
                      pc.addIceCandidate(new RTCIceCandidate(candidate))
                        .catch(e => console.error('[Error] Adding queued ICE candidate failed', e));
                  });
                  delete iceCandidateQueuesRef.current[from];
              }
          })
          .catch(e => console.error('[Error] Setting remote description for answer failed', e));
    }
  }, []);

  const handleIceCandidate = useCallback(({ candidate, from }) => {
      console.log(`[Signal] Received single ICE candidate from ${from}`);
      processIceCandidate(candidate, from);
  }, [processIceCandidate]);
  
  const handleIceCandidatesBatch = useCallback(({ candidates, from }) => {
      console.log(`[Signal] Received ICE candidate batch (${candidates.length}) from ${from}`);
      if (candidates && Array.isArray(candidates)) {
          candidates.forEach(candidate => processIceCandidate(candidate, from));
      }
  }, [processIceCandidate]);

  // =================================================================================
  //  WebRTC 信令处理器 (绑定到socket)
  // =================================================================================
  useEffect(() => {
    if (!socketRef.current) return;
    const socket = socketRef.current;

    socket.on('offer', handleOffer);
    socket.on('answer', handleAnswer);
    socket.on('ice-candidate', handleIceCandidate);
    socket.on('ice-candidates-batch', handleIceCandidatesBatch);

    return () => {
      socket.off('offer', handleOffer);
      socket.off('answer', handleAnswer);
      socket.off('ice-candidate', handleIceCandidate);
      socket.off('ice-candidates-batch', handleIceCandidatesBatch);
    };
  }, [handleOffer, handleAnswer, handleIceCandidate, handleIceCandidatesBatch]);

  // =================================================================================
  // WebRTC 连接管理器 (发起连接 & 清理)
  // =================================================================================
  useEffect(() => {
    // 必须自己上麦了、socket 已连接、本地流已准备好，才去连接别人
    if (!isMic || !socketRef.current || !localStreamRef.current) {
      return;
    }

    console.log('[Effect] Connection manager running.');
      
    // 1. 发起新连接
    micList.forEach(otherUserId => {
      // 跳过自己、空麦位、以及已经存在的连接
      if (!otherUserId || otherUserId === socketRef.current.id || peerConnections.current[otherUserId]) {
        return;
      }
      
      // 【呼叫方逻辑】为新用户创建 PC 并发送 offer
      console.log(`[Effect] Initiating connection to ${otherUserId}.`);
      const pc = createPeerConnection(otherUserId, true); // isInitiator = true
      
      pc.createOffer()
            .then(offer => pc.setLocalDescription(offer))
            .then(() => {
          console.log(`[Signal] Sending offer to ${otherUserId}`);
          socketRef.current.emit('offer', {
                offer: pc.localDescription,
            to: otherUserId,
              });
            })
        .catch(e => console.error(`[Error] Offer creation failed for ${otherUserId}`, e));
    });

    // 2. 清理掉线用户的连接
    const currentMicListSet = new Set(micList);
    Object.keys(peerConnections.current).forEach(peerId => {
      if (!currentMicListSet.has(peerId)) {
        console.log(`[Effect] Cleaning up connection for disconnected user ${peerId}`);
        if (peerConnections.current[peerId]) {
          peerConnections.current[peerId].close();
          delete peerConnections.current[peerId];
        }
        setPeers(prevPeers => {
          const newPeers = { ...prevPeers };
          delete newPeers[peerId];
          return newPeers;
        });
      }
    });

  }, [micList, isMic, createPeerConnection]); // 依赖 micList 和 isMic

  const handleMic = () => {
    // 上麦请求，不再直接修改 isMic
    if (!isMic) {
        if (!muteList.includes(userId) && !micFull) {
            console.log(`请求上麦到默认位置`);
            socketRef.current.emit("up-mic", roomId);
        }
    } else {
        // 下麦请求
        console.log('请求下麦');
        socketRef.current.emit("down-mic", roomId);
    }
  };

  const handleSendGift = (gift) => {
    if (socketRef.current) {
      socketRef.current.emit("send-gift", {
        roomId,
        gift,
        // 如果需要，您可以在此添加目标用户ID
        // targetId: hostId 
      });
      
      // 不再自动关闭礼物面板，允许连续发送多个礼物
      console.log("礼物已发送，面板保持打开状态，可继续发送");
    }
  };

  // 使用ref来跟踪是否正在处理队列更新，防止递归
  const isProcessingQueueRef = useRef(false);
  
  const handleAnimationComplete = useCallback(() => {
    // 如果已经在处理队列，则跳过
    if (isProcessingQueueRef.current) {
      console.log("已经在处理队列，跳过");
      return;
    }
    
    // 标记为正在处理
    isProcessingQueueRef.current = true;
    
    // 移除队列中第一个（已播放完毕）的礼物
    setGiftQueue(prevQueue => {
      if (prevQueue.length === 0) {
        isProcessingQueueRef.current = false;
        return prevQueue; // 防止处理空队列
      }
      
      console.log("礼物动画完成，移除队列中第一个礼物", prevQueue.length);
      // 确保不会返回空数组导致React不重新渲染
      const newQueue = prevQueue.slice(1);
      console.log("更新后的礼物队列长度:", newQueue.length);
      
      // 延迟重置处理标志，确保状态更新完成
      setTimeout(() => {
        isProcessingQueueRef.current = false;
      }, 100);
      
      return newQueue;
    });
  }, []);

  // 主持人禁麦/解禁
  const handleMute = (targetId, isMuted) => {
    if (!roomId || !hostId) return;
    if (!socketRef.current) return;
    if (isMuted) {
      socketRef.current.emit("unset-mute", { roomName: roomId, targetId });
    } else {
      socketRef.current.emit("set-mute", { roomName: roomId, targetId });
    }
  };

  // 加入房间弹窗提交
  const handleJoin = (e) => {
    e.preventDefault();
    if (!nickname.trim()) {
      alert("请输入昵称");
      return;
    }
    setShowJoinModal(false);
  };

  // 上麦动画触发
  function handleMicClick(i) {
    if (!socketRef.current) return;
    const seatIndex = i;
    const isOnMic = micList.includes(userId);
    const isTargetSeatEmpty = !micList[seatIndex];

    // 如果已经在麦上，并且点击的是一个空的麦位，则换座
    if (isOnMic && isTargetSeatEmpty) {
      console.log(`请求换座到: ${seatIndex}`);
      socketRef.current.emit("change-seat", { roomId, seatIndex });
      return;
    }

    // 如果没在麦上，点击的是空座位，并且没被禁言/麦位没满，则上麦
    if (!isOnMic && isTargetSeatEmpty && !micFull && !muteList.includes(userId)) {
      console.log(`请求上麦到: ${seatIndex}`);
      socketRef.current.emit("up-mic", roomId, seatIndex);
    }
  }

  // 重构 renderMicCircle 函数，使其布局更规整并带有序号
  function renderMicCircle() {
    // 容器和半径根据设备类型自适应 (最终版本)
    const containerSize = isMobile ? 240 : 320;
    const radius = isMobile ? containerSize / 2.7 : containerSize / 2.7;
    const angleStep = 360 / MAX_MIC;

    // 主持人席位（中心）
    const hostUser = userList.find(u => u.id === hostId);
    const hostMicIndex = micList.findIndex(id => id === hostId);
    const isHostOnMic = hostMicIndex !== -1;
    const hostIsSpeaking = isHostOnMic && speakingMap[hostId];

    // 其他麦位
    const otherMics = Array.from({ length: MAX_MIC });

    const hostMicSize = isMobile ? 70 : 90; // (最终版本)

    return (
      <div style={{ position: 'relative', width: containerSize, height: containerSize, margin: '10px auto' }}>
        {/* 渲染主持人 */}
        {hostUser && (
            <div 
              style={{
                ...styles.micCircle(hostIsSpeaking, true, isMobile),
                position: 'absolute',
                top: '50%',
                left: '50%',
                transform: `translate(-50%, -50%)`,
                width: hostMicSize,
                height: hostMicSize,
                zIndex: 2, // 确保在最上层
              }}
              onClick={() => isHostOnMic && handleMicClick(hostMicIndex)}
            >
              <img src={hostUser?.avatar || getAvatarUrl(hostUser.id)} alt="avatar" style={styles.hostAvatar(isMobile)} />
              <div style={styles.micNickname(isMobile)}>{hostUser?.nickname || '匿名'}</div>
              <div style={styles.micIconContainer}>
                <span title="主持人" style={{...styles.micIcon, color: 'gold'}}>👑</span>
                {muteList.includes(hostId) && <span title="已被禁麦" style={{...styles.micIcon, color: '#f44336'}}>🔇</span>}
              </div>
            </div>
        )}

        {/* 渲染其他8个麦位 */}
        {otherMics.map((_, i) => {
          const angle = (angleStep * i - 90) * (Math.PI / 180); // -90度，让1号位在顶部
          const micSize = isMobile ? 50 : 60; // (最终版本)
          const x = (containerSize / 2) + (radius * Math.cos(angle)) - (micSize / 2);
          const y = (containerSize / 2) + (radius * Math.sin(angle)) - (micSize / 2);
          
          const id = micList[i];

          // 如果这个麦位是主持人，则不渲染（因为已在中心渲染）
          if (id && id === hostId) {
            return (
               // 渲染一个空的占位，保持布局结构
              <div
                key={`mic-placeholder-${i}`}
                style={{
                  ...styles.emptyMic(isMobile),
                   position: 'absolute',
                  top: `${y}px`,
                  left: `${x}px`,
                   width: micSize,
                  height: micSize,
                  backgroundColor: 'transparent',
                  border: '2px dashed rgba(255, 255, 255, 0.2)',
                }}
              >
                 <span style={styles.micNumber(isMobile)}>{i + 1}</span>
              </div>
            );
          }
          
          const user = userList.find(u => u.id === id);
          const isSpeaking = speakingMap[id];
          
          // 通用麦位样式
          const micStyle = {
            ...styles.micCircle(isSpeaking, false, isMobile), // isHost总是false
            position: 'absolute',
            top: `${y}px`,
            left: `${x}px`,
            width: micSize,
            height: micSize,
          };
          
          if (!id) {
            return (
              <div
                key={`mic-${i}`}
                style={{...micStyle, ...styles.emptyMic(isMobile)}}
                onClick={() => handleMicClick(i)}
                data-mic-index={i}
              >
                <span style={styles.micNumber(isMobile)}>{i + 1}</span>
              </div>
            );
          }

          return (
            <div key={id} style={micStyle} onClick={() => handleMicClick(i)} data-mic-index={i}>
              <img src={user?.avatar || getAvatarUrl(id)} alt="avatar" style={styles.micAvatar(isMobile)} />
              <div style={styles.micNickname(isMobile)}>{user?.nickname || '匿名'}</div>
              
              <div style={styles.micIconContainer}>
                {muteList.includes(id) && <span title="已被禁麦" style={{...styles.micIcon, color: '#f44336'}}>🔇</span>}
                {id === userId && <span title="我" style={{...styles.micIcon, color: '#4fc3f7'}}>😊</span>}
              </div>

              {userId === hostId && id !== hostId && (
                <button style={styles.muteButton(isMobile)} onClick={(e) => {
                  e.stopPropagation();
                  handleMute(id, muteList.includes(id));
                }}>
                  {muteList.includes(id) ? '解禁' : '禁麦'}
                </button>
              )}
            </div>
          );
        })}
      </div>
    );
  }

  // 消息自动滚动到底部
  useEffect(() => {
    if (chatBoxRef.current) {
      chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
    }
  }, [messages]);

  // 发送消息
  function handleSendMessage(e) {
    e.preventDefault();
    const value = messageInputRef.current.value.trim();
    if (!value) return;
    if (socketRef.current) {
      socketRef.current.emit("send-message", {
        roomId,
        message: value,
        userInfo: { nickname, avatar }
      });
    }
    messageInputRef.current.value = '';
  }

  // 新增：处理背景图片上传
  const handleBackgroundChange = (e) => {
    const file = e.target.files[0];
    if (file && socketRef.current) {
      const reader = new FileReader();
      reader.onload = (event) => {
        const newBg = event.target.result;
        // 不再直接设置背景和本地存储，而是通过服务器广播来统一更新
        socketRef.current.emit('change-background', { roomId, background: newBg });
      };
      reader.readAsDataURL(file);
    }
  };

  useEffect(() => {
    // 从localStorage加载背景
    const savedBg = localStorage.getItem(`roomBackground_${roomId}`);
    if (savedBg) {
      setBackground(savedBg);
    }
  }, [roomId]);

  // 当远程媒体流(peers)发生变化时，将其附加到对应的audio元素上
  useEffect(() => {
    Object.entries(peers).forEach(([id, stream]) => {
      const audioEl = remoteAudioRefs.current[id];
      if (audioEl && audioEl.srcObject !== stream) {
        audioEl.srcObject = stream;
        // 尝试播放音频，以解决自动播放策略问题
        audioEl.play().catch(error => {
          console.warn(`为用户 ${id} 自动播放音频失败:`, error);
          // 可以在这里向用户显示一个"点击以播放声音"的按钮
        });
      }
    });
  }, [peers]);

  // 手动触发所有远程音频播放（用于调试）
  const forcePlayAll = () => {
    console.log('%c[Manual] 强制播放所有远程音频...', 'color: blue; font-weight: bold;');
    Object.entries(remoteAudioRefs.current).forEach(([id, audioEl]) => {
        if (audioEl && audioEl.srcObject) {
            console.log(`[Manual] 尝试播放用户 ${id} 的音频`);
            audioEl.play().catch(err => console.error(`[Manual] 用户 ${id} 的音频播放失败:`, err));
        } else {
            console.warn(`[Manual] 用户 ${id} 的音频元素或流不存在`);
        }
    });
  };

  return (
    <div style={styles.container(background)}>
      <GiftAnimation giftQueue={giftQueue} onAnimationComplete={handleAnimationComplete} />
      <div style={styles.overlay}></div>

      {/* 顶部信息栏 */}
      <div style={styles.topBar(isMobile)}>
        <div style={styles.roomInfo(isMobile)}>
          <p>房间ID: {roomId}</p>
          <p>热度: 1014</p>
        </div>
        <div style={styles.userIcons}>
          {/* 用户头像列表 */}
          {userList.slice(0, 5).map(u => (
            <img key={u.id} src={u.avatar || getAvatarUrl(u.id)} alt={u.nickname} title={u.nickname} style={styles.userIcon(isMobile)} />
          ))}
          {userList.length > 5 && <div style={{...styles.userIcon(isMobile), ...styles.userCount(isMobile)}}>+{userList.length - 5}</div>}
          <div style={styles.totalUserCount(isMobile)}>{userList.length}人</div>
        </div>
      </div>

      {/* 麦位区 */}
      <div style={styles.micArea}>
        {renderMicCircle()}
      </div>
      
      {/* 听众 & 消息 & 操作区 */}
       <div style={styles.bottomSection(isMobile)}>
         {/* 消息区 */}
         <div ref={chatBoxRef} style={styles.chatBox(isMobile)}>
          {messages.map((msg, idx) => (
            <div key={idx} style={styles.chatMessage(msg.id === userId)}>
              {msg.type === 'system' ? (
                <span style={{color: '#aaa', fontStyle: 'italic'}}>{msg.message}</span>
              ) : (
                <span>
                  <b>{msg.nickname || msg.id}: </b>{msg.message}
                </span>
              )}
            </div>
          ))}
         </div>

         {/* 底部操作区 */}
         <div style={styles.actionArea(isMobile)}>
           {/* 聊天输入 */}
           <form onSubmit={handleSendMessage} style={styles.chatForm}>
             <input
               ref={messageInputRef}
               style={styles.chatInput}
               placeholder="说点什么..."
             />
             <button type="submit" style={styles.chatSendButton(isMobile)}>发送</button>
           </form>

           {/* 其他按钮 */}
           <div style={styles.controls}>
            {userId === hostId && (
              <>
                <input
                    type="file"
                    ref={fileInputRef}
                    onChange={handleBackgroundChange}
                    style={{ display: 'none' }}
                    accept="image/*"
                />
                <button style={styles.controlButton(isMobile)} onClick={() => fileInputRef.current.click()} title="更换背景">🎨</button>
              </>
            )}
             <button style={styles.controlButton(isMobile)} onClick={() => setIsGiftModalOpen(true)} title="送礼物">🎁</button>
             <button style={styles.controlButton(isMobile)} onClick={forcePlayAll} title="强制播放">🔊</button>
             <button style={styles.controlButton(isMobile)} onClick={handleMic} disabled={muteList.includes(userId) || micFull}>
               {isMic ? "下麦" : "上麦"}
             </button>
           </div>
         </div>
      </div>
      
      {showJoinModal && (
        <div style={{
          position:'fixed',top:0,left:0,right:0,bottom:0,background:'rgba(0,0,0,0.45)',zIndex:1000,display:'flex',alignItems:'center',justifyContent:'center',backdropFilter:'blur(8px)'}}>
          <form onSubmit={handleJoin} style={{
            background:'rgba(30,34,54,0.95)',
            padding:40,
            borderRadius:24,
            minWidth:320,
            boxShadow:'0 8px 32px 0 rgba(31,38,135,0.37)',
            border:'1.5px solid rgba(255,255,255,0.18)',
            display:'flex',flexDirection:'column',alignItems:'center',
            position:'relative',
          }}>
            <h3 style={{color:'#fff',fontWeight:700,letterSpacing:2,marginBottom:18,fontSize:22,textShadow:'0 2px 8px #0008'}}>加入语音房间</h3>
            <div style={{marginBottom:18,display:'flex',flexDirection:'column',alignItems:'center'}}>
              <div style={{
                width:72,height:72,borderRadius:'50%',marginBottom:10,
                background:'linear-gradient(135deg,#3a86ff 0%,#8338ec 100%)',
                boxShadow:'0 0 24px 4px #3a86ff55,0 0 0 6px #fff2',
                display:'flex',alignItems:'center',justifyContent:'center',
                border:'3px solid #fff6',
                animation:'avatar-rotate 2.5s linear infinite',
                position:'relative',
                overflow:'hidden',
              }}>
                <img src={avatar || getAvatarUrl('default')} alt="avatar" style={{width:62,height:62,borderRadius:'50%',boxShadow:'0 0 8px #fff8'}} />
                <style>{`@keyframes avatar-rotate{0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}}`}</style>
            </div>
              <button type="button" onClick={() => setAvatar(getAvatarUrl(Date.now().toString()))} style={{
                background:'linear-gradient(90deg,#3a86ff 0%,#8338ec 100%)',
                color:'#fff',border:'none',borderRadius:12,padding:'4px 18px',
                fontWeight:600,boxShadow:'0 2px 8px #3a86ff44',cursor:'pointer',
                fontSize:14,marginTop:2,transition:'all 0.2s',
                letterSpacing:1
              }}>随机头像</button>
            </div>
            <div style={{marginBottom:18,width:'100%'}}>
              <input value={nickname} onChange={e=>setNickname(e.target.value)} placeholder="请输入昵称" style={{
                width:'100%',padding:'12px 18px',borderRadius:14,border:'none',
                background:'rgba(255,255,255,0.12)',color:'#fff',fontSize:16,
                boxShadow:'0 1px 4px #3a86ff22',outline:'none',
                marginBottom:2,transition:'box-shadow 0.2s',
                fontWeight:500,letterSpacing:1
              }} />
            </div>
            <button type="submit" style={{
              width:'100%',padding:'12px 0',borderRadius:16,border:'none',
              background:'linear-gradient(90deg,#3a86ff 0%,#8338ec 100%)',
              color:'#fff',fontWeight:700,fontSize:17,letterSpacing:2,
              boxShadow:'0 4px 16px #3a86ff33',cursor:'pointer',transition:'all 0.2s',
              marginTop:4
            }}>进入房间</button>
          </form>
        </div>
      )}
      <GiftComponent
        visible={isGiftModalOpen}
        onClose={() => setIsGiftModalOpen(false)}
        onSendGift={handleSendGift}
      />
      <audio ref={localAudioRef} autoPlay controls muted style={{display:'none'}} />
      <div style={{display:'none'}}>
        {Object.keys(peers).map((id) => (
          <audio
            key={id}
            ref={el => (remoteAudioRefs.current[id] = el)}
            autoPlay
            playsInline // 增强移动端兼容性
            controls
          />
        ))}
      </div>
    </div>
  );
};

// --- 全新的样式对象 (最终修复版) ---
const styles = {
  container: (bg) => ({
    width: '100vw',
    height: 'calc(var(--vh, 1vh) * 100)',
    backgroundImage: `url(${bg})`,
    backgroundSize: 'cover',
    backgroundPosition: 'center',
    color: '#fff',
    display: 'flex',
    flexDirection: 'column',
    position: 'relative',
    overflow: 'hidden',
  }),
  overlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.3)',
  },
  topBar: (isMobile) => ({
    position: 'relative',
    zIndex: 2,
    display: 'flex',
    justifyContent: 'space-between',
    padding: isMobile ? '8px 10px' : '10px 15px',
    backgroundColor: 'rgba(0,0,0,0.2)',
    flexShrink: 0, // 禁止收缩
  }),
  roomInfo: (isMobile) => ({
    fontSize: isMobile ? '10px' : '12px',
  }),
  userIcons: {
    display: 'flex',
    alignItems: 'center',
  },
  userIcon: (isMobile) => ({
    width: isMobile ? '24px' : '30px',
    height: isMobile ? '24px' : '30px',
    borderRadius: '50%',
    border: '1px solid #fff',
    marginLeft: '-10px',
    background: '#555',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  }),
  userCount: (isMobile) => ({
    fontSize: isMobile ? '10px' : '12px',
    color: '#fff',
    fontWeight: 'bold',
  }),
  totalUserCount: (isMobile) => ({
    marginLeft: '15px',
    backgroundColor: 'rgba(0,0,0,0.5)',
    padding: isMobile ? '4px 8px' : '5px 10px',
    borderRadius: '15px',
    fontSize: isMobile ? '10px' : '12px',
  }),
  micArea: {
    position: 'relative',
    zIndex: 2,
    flex: 1, // 填充剩余空间
    minHeight: 0, // 允许收缩
    overflow: 'hidden', // 裁剪溢出内容
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: '10px 0',
  },
  bottomSection: (isMobile) => ({
    position: 'relative',
    zIndex: 2,
    padding: '8px',
    display: 'flex',
    flexDirection: 'column',
    gap: '8px',
    backgroundColor: 'rgba(0,0,0,0.2)',
    flexShrink: 0, // 禁止收缩
    maxHeight: '30vh', // 限制最大高度
    overflow: 'hidden', // 裁剪内部溢出
  }),
  chatBox: (isMobile) => ({
    flex: 1, // 填充 bottomSection 内的可用空间
    minHeight: 0, // 允许在 flex 布局中收缩
    overflowY: 'auto',
    padding: '8px',
    fontSize: isMobile ? '12px' : '14px',
  }),
  chatMessage: (isMe) => ({
    textAlign: isMe ? 'right' : 'left',
    marginBottom: '5px',
  }),
  controls: {
    display: 'flex',
    alignItems: 'center',
    gap: '10px',
  },
  controlButton: (isMobile) => ({
    backgroundColor: 'rgba(255, 255, 255, 0.2)',
    border: '1px solid rgba(255, 255, 255, 0.5)',
    color: '#fff',
    padding: isMobile ? '0' : '8px 16px',
    width: isMobile ? '40px' : 'auto',
    height: '40px',
    borderRadius: isMobile ? '50%' : '20px',
    cursor: 'pointer',
    fontSize: isMobile ? '18px' : '14px',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    flexShrink: 0,
  }),
  micCircle: (isSpeaking, isHost, isMobile) => ({
    position: 'absolute',
    width: isMobile ? '60px' : '80px',
    height: isMobile ? '60px' : '80px',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    transition: 'all 0.3s ease',
    cursor: 'pointer',
    background: 'rgba(255, 255, 255, 0.1)',
    borderRadius: '50%',
    border: '2px solid rgba(255, 255, 255, 0.3)',
    boxShadow: `
      inset 0 0 15px rgba(180, 220, 255, 0.2)
      ${isSpeaking ? ', 0 0 25px 5px #4fc3f7, 0 0 15px 2px #fff' : ''}
      ${isHost ? ', 0 0 20px 3px gold' : ''}
    `,
    transform: isSpeaking ? 'scale(1.05)' : 'scale(1)',
    '&:hover': {
      transform: 'scale(1.1)',
      boxShadow: '0 0 25px rgba(180, 220, 255, 0.6)',
    },
  }),
  emptyMic: (isMobile) => ({
    opacity: 0.5,
    borderStyle: 'dashed',
    color: 'rgba(255,255,255,0.7)',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    background: 'rgba(0,0,0,0.2)',
  }),
  micAvatar: (isMobile) => ({
    width: isMobile ? '40px' : '48px',
    height: isMobile ? '40px' : '48px',
    borderRadius: '50%',
    objectFit: 'cover',
  }),
  hostAvatar: (isMobile) => ({
    width: isMobile ? '56px' : '72px',
    height: isMobile ? '56px' : '72px',
    borderRadius: '50%',
    objectFit: 'cover',
  }),
  micNickname: (isMobile) => ({
    fontSize: isMobile ? '10px' : '12px',
    marginTop: '4px',
    maxWidth: '70px',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    whiteSpace: 'nowrap',
    textShadow: '0 0 3px #000',
  }),
  micIconContainer: {
    position: 'absolute',
    bottom: '18%',
    right: '2px',
    display: 'flex',
    gap: '2px',
  },
  micIcon: {
    fontSize: '11px',
    background: 'rgba(0, 0, 0, 0.5)',
    borderRadius: '50%',
    width: '16px',
    height: '16px',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    lineHeight: 1,
  },
  muteButton: (isMobile) => ({
    position: 'absolute',
    bottom: '-20px',
    left: '50%',
    transform: 'translateX(-50%)',
    background: 'rgba(255, 99, 71, 0.7)',
    color: 'white',
    border: 'none',
    borderRadius: '8px',
    padding: '2px 6px',
    fontSize: '12px',
    cursor: 'pointer',
    opacity: 0.8,
    '&:hover': {
      opacity: 1,
    }
  }),
  micNumber: (isMobile) => ({
    fontSize: isMobile ? '22px' : '24px',
    fontWeight: 'bold',
    color: 'rgba(255,255,255,0.7)',
    textShadow: '0 0 5px rgba(0,0,0,0.5)',
  }),
  actionArea: (isMobile) => ({
    display: 'flex',
    alignItems: 'center',
    gap: '10px',
  }),
  chatForm: {
    flex: 1,
    display: 'flex',
    alignItems: 'center',
  },
  chatInput: {
    flex: 1,
    background: 'rgba(0,0,0,0.3)',
    border: '1px solid rgba(255,255,255,0.3)',
    color: '#fff',
    borderRadius: '20px',
    padding: '8px 15px',
    fontSize: '14px',
    height: '40px',
  },
  chatSendButton: (isMobile) => ({
    marginLeft: '8px',
    background: '#3a86ff',
    color: '#fff',
    border: 'none',
    borderRadius: '20px',
    height: '40px',
    padding: '0 16px',
    cursor: 'pointer',
    flexShrink: 0,
    display: isMobile ? 'none' : 'block',
  }),
};

export default VoiceRoom; 